package api

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
	"web-im/etc"
	"web-im/signature"
)

const baseURL = "https://console.tim.qq.com/v4"

func CreateGroup(name string) (string, error) {
	params := map[string]interface{}{
		"Owner_Account": etc.Admin,
		"Type": "Public",
		"Name": name,
	}

	body, err := json.Marshal(params)
	if err != nil {
		return "", err
	}

	return request(http.MethodPost, "group_open_http_svc/create_group", string(body))
}

func SendGroupMessage(groupId string, message string) (string, error) {
	params := map[string]interface{}{
		"GroupId": groupId,
		"Random": rand.Intn(9999),
		"MsgBody": []interface{}{
			map[string]interface{}{
				"MsgType": "TIMTextElem",
				"MsgContent": map[string]interface{}{"Text": message},
			},
		},
	}

	body, err := json.Marshal(params)
	if err != nil {
		return "", err
	}

	return request(http.MethodPost, "group_open_http_svc/send_group_msg", string(body))
}

func Logout(account string) error {
	params := map[string]interface{}{
		"Identifier": account,
	}

	body, err := json.Marshal(params)
	if err != nil {
		return err
	}

	res, err := request(http.MethodPost, "im_open_login_svc/kick", string(body))
	if err != nil {
		return err
	}

	var result map[string]interface{}

	err = json.Unmarshal([]byte(res), &result)
	if err != nil {
		return fmt.Errorf("result: %s", res)
	}

	if v, ok := result["ActionStatus"]; ok {
		if status, ok := v.(string); ok && status == "OK" {
			return nil
		} else {
			return fmt.Errorf("result: %s", res)
		}
	} else {
		return fmt.Errorf("result: %s", res)
	}
}

func SendMessage(account, message string) (string, error) {
	params := map[string]interface{}{
		"SyncOtherMachine": 2,
		"To_Account": account,
		"MsgLifeTime": 3600,
		"MsgRandom": rand.Intn(9999),
		"MsgTimeStamp": time.Now().Unix(),
		"MsgBody": []interface{}{
			map[string]interface{}{
				"MsgType": "TIMTextElem",
				"MsgContent": map[string]interface{}{"Text": message},
			},
		},
	}

	body, err := json.Marshal(params)
	if err != nil {
		return "", err
	}

	return request(http.MethodPost, "openim/sendmsg", string(body))
}

func request(method string, uri string, params string) (string, error) {
	api, err := parseURL(uri)
	if err != nil {
		return "", err
	}

	r, err := http.NewRequest(method, api, strings.NewReader(params))
	if err != nil {
		return "", err
	}

	c := &http.Client{}
	res, err := c.Do(r)

	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}

	return string(body), nil
}

func parseURL(uri string) (string, error) {
	sign, err := signature.New(etc.AppID).WithAccountType(etc.AccountType).Generate(etc.Admin, etc.PrivateKey)
	if err != nil {
		return "", err
	}

	values := url.Values{}

	values.Set("sdkappid", fmt.Sprintf("%d", etc.AppID))
	values.Set("identifier", etc.Admin)
	values.Set("usersig", sign)
	values.Set("random", strconv.Itoa(rand.Intn(9999)))
	values.Set("contenttype", "json")

	return fmt.Sprintf("%s/%s?%s", baseURL, uri, values.Encode()), nil
}